package ev.ftw.dna;

import java.io.File;
import java.io.FileNotFoundException;
import java.io.PrintWriter;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.Scanner;
import java.util.TreeSet;

import ev.ftw.gff.FragConocido;
import ev.ftw.gff.Fragmento;
import ev.ftw.gff.GFFFileIO;
import ev.maths.handlers.AncientEgyptianDecomposition;
import ev.maths.handlers.DiscreteWaveletTransform;
import ev.maths.handlers.wavelets.Haar02Orthogonal;

/**
 * Clase para trabajar con un cromosoma.
 * 
 * @date 01.08.2012
 * @author Enrique Vázquez de Luis
 */
public class Cromosoma {
	
	final static float LIMITE_EXP_WLT = 2.5f; //Mínimo límite de un salto para Wavelets. (VALOR POR DEFECTO)
	final static float LIMITE_EXP_MEDIA = 9.5f; //Mínimo límite de la média para que se considere expresado. (VALOR POR DEFECTO)
	final static int LIMITE_TAM = 75; //Mínimo tamaño de un fragmento expresado.
	final static int LIMITE_TAM_NO_EXPRESADO = 100; //Mínimo tamaño de un fragmento no expresado para limitar uno si expresado.
	final static float LIMITE_DIFERENCIA_MEDIA = 4.5f; //Mínimo límite de diferencia con la media pra que se considere un error.
	final static float LIMITE_WLT_MIN = 3; //Máximo límite de salto WLT para que se anule con el filtro WLT. (VALOR POR DEFECTO).


	HashMap<Integer, Float> expresion;//@deprecated 
	ArrayList<Sonda> sondas; //Array de Sondas leidas de un fichero
	float completo[]; //Array de expresión completo y equiespaciado
	int resolucion; //Resolución del array anterior, el número de nucleótidos que representa cada elemento del array
	
	String tipo; //Tipo de cromosoma
	String nombre; //Nombre del cromosoma
	boolean pasoVariable; //Paso fijo o variable
	String cromosoma; 
	int span; //Tamaño de la sonda leída
	char direccion; //Dirección de lectura
	
	/**
	 * Getter del nombre del cromosoma
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return El nombre del cromosoma.
	 */
	public String getNombre(){
		return this.nombre;
	}
	
	/**
	 * Constructor sin parámetros.<br>
	 * Inicializa los atributos a los valores por defecto.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public Cromosoma(){
		//expresion = new HashMap<Integer, Float>();
		sondas = new ArrayList<Sonda>();
		this.setDefault();
	}
	
	/**
	 * Función que inicializa los atributos a sus valores por defecto.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void setDefault(){
		this.tipo = "tipo";
		this.nombre = "cromosoma";
		this.pasoVariable = true;
		this.cromosoma = "chromosome1";
		this.span = 25;
		this.direccion = '.';
	}
	
	/**
	 * Constructor con todos los parámetros básicos del cromosoma.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param tipo Tipo de cromosoma.
	 * @param nombre Nombre del cromosoma.
	 * @param pasoVariable Paso variable (true) o fijo (false).
	 * @param cromosoma Cromosoma.
	 * @param span Tamaño de las sondas.
	 * @param direccion Dirección de lectura.
	 * @param sondas Array con las sondas que representan el cromosoma.
	 */
	public Cromosoma(String tipo, String nombre, boolean pasoVariable, String cromosoma, int span, char direccion, ArrayList<Sonda> sondas){
		this.tipo = tipo;
		this.nombre = nombre;
		this.pasoVariable = pasoVariable;
		this.cromosoma = cromosoma;
		this.span = span;
		this.sondas = sondas;
		this.direccion = direccion;
		
		this.rellenaCompletoSondas();
	}
	
	/**
	 * Función para clonar un objeto cromosoma.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	@SuppressWarnings("unchecked")
	public Cromosoma clone(){
		Cromosoma copia = new Cromosoma();
		copia.tipo = this.tipo;
		copia.nombre = this.nombre;
		copia.pasoVariable = this.pasoVariable;
		copia.cromosoma = this.cromosoma;
		copia.span = this.span;
		if(this.sondas != null) copia.sondas = (ArrayList<Sonda>)this.sondas.clone();
		copia.direccion = this.direccion;
		//if(this.expresion != null)copia.expresion = (HashMap<Integer, Float>)this.expresion.clone();
		if(this.completo != null)copia.completo = this.completo.clone();
		copia.resolucion = this.resolucion;
		
		return copia;
	}
	
	/*
	 * track type=wiggle_0 name=10
		variableStep chrom=chromosome1 span=25
		5353	9.75
		5722	8.65
		6312	13.6
		6639	7.42
		6898	7.3
		7694	11.4
		10091	8.99
		11263	6.63
		11284	7.98
		12423	7.38
		12443	9.21
		12463	8.6
		12674	6.85
		12695	7.24
	 */
	
	/**
	 * Función que se encarga de leer un fichero de expresión.
	 * 
	 * @deprecated Deprecada porque ya no se usa el HashMap "expresion".
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param ruta La ruta del fichero que se ha de leer.
	 */
	public void leerFicheroExpresion(String ruta){
		if(this.sondas == null) this.sondas = new ArrayList<Sonda>();
		String aux;
		float auxf;
		try {
			Scanner s = new Scanner(new File(ruta));
			System.out.println(s.next() + " " + s.next() + " " + s.next());
			System.out.println(s.next() + " " + s.next() + " " + s.next());
			aux = s.next();
			
			while(aux.compareToIgnoreCase("track") != 0){
				auxf = Float.parseFloat(s.next());
				sondas.add(new Sonda(Integer.parseInt(aux), auxf));
				//expresion.put(Integer.parseInt(aux), auxf);
				aux = s.next();
			}
			
			//System.out.println("Tamaño: " + expresion.size());
			//System.out.println(expresion.get(Integer.parseInt("11263")));
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch (Exception e){
			e.printStackTrace();
			//System.out.println("Tamaño: " + expresion.size());
			//System.out.println(expresion.get(Integer.parseInt("11263")));			
		}
		
	}
	
	/**
	 * Función que se encarga de comprobar si hay o no hay expresión en cada posición del genoma. </br>
	 * De momento no muy útil.
	 * 
	 * @deprecated Deprecada porque se han creado las funciónes finales de búsqueda de expresión.
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void compruebaExpresion(){
		int i;
		for(i = 0; i < completo.length; i++){
			if(completo[i] > 11)System.out.println("*");
			else System.out.println("-");
		}
		System.out.println(i + "     " + completo.length);
	}
	
	/**
	 * Función que se encarga de comprobar la expresión en las sondas en vez de en el array.
	 * 
	 * @deprecated Deprecada porque se han creado las funciónes finales de búsqueda de expresión.
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void compruebaSondas(){
		int i;
		for(i = 0; i < sondas.size(); i++){
			if(sondas.get(i).getValor() > 11)System.out.println(sondas.get(i).getPosicion() + ": E");
			else System.out.println(sondas.get(i).getPosicion() + ": N");
		}
		System.out.println(i + "     " + completo.length);
	}
	
	/**
	 * Función que se encarga de rellenar el array de expresión completo a través del hashMap
	 * de expresión.
	 * 
	 * @deprecated Deprecada porque ya no se usa el HashMap "expresion".
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void rellenaCompleto(){
		completo = new float[expresion.size()];		
		Iterator<Integer> it = expresion.keySet().iterator();
		for(int i = 0; it.hasNext(); i++){
			completo[i] = expresion.get(it.next());
		}
		this.expresion = null;
		this.resolucion = 1;
	}
	
	/**
	 * Función que se encarga de rellenar el Array completo a través del array de sondas.</br>
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void rellenaCompletoSondas(){
		if(sondas == null) return;
		Sonda s = sondas.get(sondas.size()-1);
		int tamanno = s.getPosicion() + s.getTamanno()+1;
		completo = new float[tamanno];
		for(int i = 0; i < sondas.size(); i++){
			s = sondas.get(i);
			int posDNA = s.getPosicion();
			for(int j = 0; j < s.getTamanno(); j++){
				if(completo[posDNA+j] == 0) completo[posDNA+j] = s.getValor();
				else{
					completo[posDNA+j] = (s.getValor() + completo[posDNA+j])/2;
				}
			}
		}
		this.sondas = null;
		this.resolucion = 1;
	}
	
	/**
	 * Función de Debug.</br>
	 * Imprime por consola todos los elementos del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void D_printCompleto(){
		for(int i = 1; i < completo.length; i++){
			System.out.println(completo[i]);
		}
	}
	
	/**
	 * Función de Debug.</br>
	 * Imprime por consola todos los elementos del array "completo" desde ini hasta fin.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param ini posición inicial para imprimir.
	 * @param fin posición final para imprimir.
	 */
	public void D_printCompleto(int ini, int fin){
		for(int i = ini; i <= fin; i++){
			System.out.println(completo[i]);
		}
	}
	
	/**
	 * Imprime la información completa del cromosoma por el flujo de impresión p.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param p Flujo por el que se imprimirá el cromosoma.
	 */
	public void printFileCompleto(PrintWriter p){
		p.println("track type=" + this.tipo +" name=" + this.nombre);
		if(this.pasoVariable)p.print("variableStep");
		else p.print("fixedStep");
		p.println(" chrom=" + this.cromosoma + " span="+this.resolucion);
		for(int i = 1; i < completo.length; i++){
			p.println((i-1)*this.resolucion+1 + "\t" + completo[i]);
		}
		p.flush();
	}
	
	/**
	 * Función de Debug.</br>
	 * Imprime en un fichero, respetando el formato wig los elementos del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param fichero Fichero de destino.
	 */
	public void D_printFileCompleto(String fichero){
		try {
			PrintWriter p = new PrintWriter(new File(fichero));
			p.println("track type=" + this.tipo +" name=" + this.nombre);
			if(this.pasoVariable)p.print("variableStep");
			else p.print("fixedStep");
			p.println(" chrom=" + this.cromosoma + " span="+this.resolucion);
			for(int i = 1; i < completo.length; i++){
				p.println((i-1)*this.resolucion+1 + "\t" + completo[i]);
			}
			p.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		}
	}
	
	/**
	 * @deprecated
	 * Función de Debug.</br>
	 * Imprime en un fichero, respetando el formato wig, los elementos del array "completo" desde
	 * la posición ini hasta fin.</br>
	 * Función deprecada porque no tiene sentido un wig cuya posición de inicio no sea 1.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param fichero Fichero donde volcar el cromosoma.
	 * @param ini Posición inicial del volcado.
	 * @param fin Posición final del volcado.
	 */
	public void D_printFileCompleto(String fichero, int ini, int fin){
		try {
			PrintWriter p = new PrintWriter(new File(fichero));
			p.println("track type=" + this.tipo +" name=" + this.nombre);
			if(this.pasoVariable)p.print("variableStep");
			else p.print("fixedStep");
			p.println(" chrom=" + this.cromosoma + " span="+this.resolucion);
			for(int i = ini; i <= fin; i++){
				//p.println(i + "\t" + String.format("%.2f", completo[i]));
				p.println((i-1)*this.resolucion+1 + "\t" + completo[i]);
				System.out.println(i);
			}
			p.flush();
		} catch (FileNotFoundException e) {
			e.printStackTrace();
		} catch(Exception e){
			e.printStackTrace();
		}
	}
	
	/**
	 * Getter de "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return El array "completo".
	 */
	public float[] getCompleto(){
		return this.completo;
	}
	
	/**
	 * Getter de "resolución".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return La resolución del array "completo".
	 */
	public int getResolucion(){
		return this.resolucion;
	}
	
	/**
	 * Reduce a la mitad la resolución del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void reduceResolucion2(){
		float [] nuevoCompleto = new float[this.completo.length/2];
		for(int i = 1, j = 2; i < nuevoCompleto.length && j < this.completo.length; i++, j += 2){
			if(this.completo[j] == 0 || this.completo[j-1] == 0) nuevoCompleto[i] = (this.completo[j] + this.completo[j-1]);
			else nuevoCompleto[i] = (this.completo[j] + this.completo[j-1])/2;
		}
		this.completo = nuevoCompleto;
		this.resolucion *= 2;
	}
	
	/**
	 * Reduce a la tercera parte la resolución del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 */
	public void reduceResolucion3(){
		float [] nuevoCompleto = new float[this.completo.length/3];
		int n = 3;
		for(int i = 1, j = 3; i < nuevoCompleto.length && j < this.completo.length; i++, j += 3){
			n = 3;
			if(this.completo[j] == 0) n--;
			if(this.completo[j-1] == 0) n--;
			if(this.completo[j-2] == 0) n--;
			if(n == 0) nuevoCompleto[i] = (this.completo[j] + this.completo[j-1] + this.completo[j-2]); 
			else nuevoCompleto[i] = (this.completo[j] + this.completo[j-1] + this.completo[j-2])/n;
		}
		this.completo = nuevoCompleto;
		this.resolucion *= 3;
	}
	
	/**
	 * Reduce a la enésima parte la resolución del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param n En cuánto tiene que reducir la resolución.
	 */
	public void reduceResolucion(int n){
		if(n <= 1 || this.completo.length/n < 1 || this.completo.length == 1) return;
		float [] nuevoCompleto = new float[this.completo.length/n];
		int nValores = 3;
		float resultado = 0;
		for(int i = 1, j = n; i < nuevoCompleto.length && j < this.completo.length; i++, j += n){
			nValores = n;
			resultado = 0;
			for(int k = 0; k < n; k++){
				resultado += this.completo[j-k];
				if(this.completo[j-k] == 0)nValores--;
			}
			if(nValores == 0) nuevoCompleto[i] = resultado; 
			else nuevoCompleto[i] = resultado/nValores;
		}
		this.completo = nuevoCompleto;
		this.resolucion *= n;
	}
	
	/**
	 * Aumenta la resolución del array "completo". </br>
	 * La máxima resolución es 1 y se consigue <i>aumentaResolucion(this.resolucion)</i>.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param n En cuanto tiene que aumentar la resolución del array "completo".
	 */
	public void aumentaResolucion(int n){
		if(n <= 1 || this.resolucion == 1 || this.resolucion/n < 1) return;
		float [] nuevoCompleto = new float[this.completo.length*n];
		for(int i = 1;i < this.completo.length; i++){
			for(int j=0; j < n; j++){
				nuevoCompleto[i*n+j] = this.completo[i];
			}
		}
		this.completo = nuevoCompleto;
		this.resolucion /= n;
	}
	
	/**
	 * Función para suavizar los valores del array "completo" en base a un ancho de banda.<br>
	 * Hay que tener en cuenta que al aplicar este filtro n hace referencia a posiciones en el array
	 * y no a posiciones concretas del cromosoma (salvo que la resolución sea 1).
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param n Elementos a derecha e izquierda que se deben tener en cuenta. 
	 */
	public void bandwith(int n){
		int i = 0;
		float resultado = 0;
		float [] nuevoCompleto = new float[this.completo.length];
		int nValores = 2*n+1;
		
		//Primer tramo, no hay suficientes valores por la izquierda
		for(i = 1; i < n; i++){
			resultado = this.completo[i];
			nValores = n+1+i;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i+j];
				if(this.completo[i+j] == 0) nValores--;
			}
			for(int j = 1; i-j >= 1; j++){
				resultado += this.completo[i-j];
				if(this.completo[i-j] == 0) nValores--;
			}
			nuevoCompleto[i] = resultado / nValores;
		}
		
		//Segundo tramo, hay valores suficientes a ambos lados
		for(; i < this.completo.length-n; i++){
			resultado = this.completo[i];
			nValores = 2*n+1;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i+j] + this.completo[i-j];
				if(this.completo[i+j] == 0) nValores--;
				if(this.completo[i-j] == 0) nValores--;
			}
			nuevoCompleto[i] = resultado / nValores;
		}
		
		//Tercer tramo, no hay valores suficientes por la derecha
		for(; i < this.completo.length; i++){
			resultado = this.completo[i];
			nValores = n+1+i;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i-j];
				if(this.completo[i-j] == 0) nValores--;
			}
			for(int j = 1; i+j < this.completo.length; j++){
				resultado += this.completo[i+j];
				if(this.completo[i+j] == 0) nValores--;
			}
			nuevoCompleto[i] = resultado / nValores;
		}
		
		this.completo = nuevoCompleto;
	}
		
	/**
	 * Filtro de eliminación de errores muy claros en el array "Completo".<br>
	 * Busca valores únicos que se alejen mucho de la media de los n valores anteriores y n valores siguientes.<br>
	 * Hay que tener en cuenta que al aplicar este filtro n hace referencia a posiciones en el array
	 * y no a posiciones concretas del cromosoma (salvo que la resolución sea 1).
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param n Elementos a derecha e izquierda con que se hará la media para comparar.
	 */
	public void eliminaErroneos(int n){
		int i = 0;
		float resultado = 0;
		float [] nuevoCompleto = new float[this.completo.length];
		int nValores = 2*n+1;
		float diferencia;
		
		//Primer tramo, no hay suficientes valores por la izquierda
		for(i = 1; i < n; i++){
			resultado = 0;
			nValores = n+i;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i+j];
				if(this.completo[i+j] == 0) nValores--;
			}
			for(int j = 1; i-j >= 1; j++){
				resultado += this.completo[i-j];
				if(this.completo[i-j] == 0) nValores--;
			}
			resultado /= nValores; //Media
			diferencia = this.completo[i] - resultado; //Diferencia del valor con la media 
			if(diferencia > LIMITE_DIFERENCIA_MEDIA || diferencia < -LIMITE_DIFERENCIA_MEDIA) nuevoCompleto[i] = resultado; //Si la diferencia es muy grande, se cambia por la media
			else nuevoCompleto[i] = this.completo[i]; //Si no, se deja el valor antiguo
		}
		
		//Segundo tramo, hay valores suficientes a ambos lados
		for(; i < this.completo.length-n; i++){
			resultado = this.completo[i];
			nValores = 2*n;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i+j] + this.completo[i-j];
				if(this.completo[i+j] == 0) nValores--;
				if(this.completo[i-j] == 0) nValores--;
			}
			resultado /= nValores; //Media
			diferencia = this.completo[i] - resultado; //Diferencia del valor con la media 
			if(diferencia > LIMITE_DIFERENCIA_MEDIA || diferencia < -LIMITE_DIFERENCIA_MEDIA) nuevoCompleto[i] = resultado; //Si la diferencia es muy grande, se cambia por la media
			else nuevoCompleto[i] = this.completo[i]; //Si no, se deja el valor antiguo
		}
		
		//Tercer tramo, no hay valores suficientes por la derecha
		for(; i < this.completo.length; i++){
			resultado = this.completo[i];
			nValores = n+1;
			for(int j = 1; j <= n; j++){
				resultado += this.completo[i-j];
				if(this.completo[i-j] == 0) nValores--;
			}
			for(int j = 1; i+j < this.completo.length; j++){
				resultado += this.completo[i+j];
				if(this.completo[i+j] == 0) nValores--;
			}
			resultado /= nValores; //Media
			diferencia = this.completo[i] - resultado; //Diferencia del valor con la media 
			if(diferencia > LIMITE_DIFERENCIA_MEDIA || diferencia < -LIMITE_DIFERENCIA_MEDIA) nuevoCompleto[i] = resultado; //Si la diferencia es muy grande, se cambia por la media
			else nuevoCompleto[i] = this.completo[i]; //Si no, se deja el valor antiguo
		}
		
		this.completo = nuevoCompleto;
	}
	
	
	/**
	 * Función que compara las resoluciones de dos cromosomas y los pone ambos a la misma.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param aComparar Cromosoma para comparar.
	 * @return La resolución común.
	 */
	public int comunResolucion(Cromosoma aComparar){
		if(this.resolucion == aComparar.getResolucion())return this.resolucion;
		int mayorResolucion = 0;
		if(aComparar.getResolucion() < this.resolucion) mayorResolucion = aComparar.getResolucion();
		else mayorResolucion = this.resolucion;
		
		//Si no son divisibles una por otra se pone a 1 la resolución de ambas
		if(this.resolucion % mayorResolucion != 0 || aComparar.getResolucion() % mayorResolucion != 0){
			this.aumentaResolucion(this.resolucion);
			aComparar.aumentaResolucion(aComparar.getResolucion());
		}
		//Si no, se ponen a la mayor
		else{
			this.aumentaResolucion(this.resolucion/mayorResolucion);
			aComparar.aumentaResolucion(aComparar.getResolucion()/mayorResolucion);
		}
		return this.resolucion;
	}
	
	/**
	 * Función que suma los valores de un cromosoma a los del actual.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param aSumar Cromosoma a sumar.
	 */
	public void suma(Cromosoma aSumar){
		this.comunResolucion(aSumar);
		int tam = 0;
		if(this.completo.length <= aSumar.getCompleto().length) tam = this.completo.length;
		else tam = aSumar.getCompleto().length;
		for(int i = 1; i < tam; i++){
			this.completo[i] += aSumar.getCompleto()[i];
		}
		
	}
	
	/**
	 * Función que resta los valores de un cromosoma a los del actual.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param aRestar Cromosoma a restar.
	 */
	public void resta(Cromosoma aRestar){
		this.comunResolucion(aRestar);
		int tam = 0;
		if(this.completo.length <= aRestar.getCompleto().length) tam = this.completo.length;
		else tam = aRestar.getCompleto().length;
		for(int i = 1; i < tam; i++){
			this.completo[i] -= aRestar.getCompleto()[i];
		}
	}
	
	/**
	 * Función que multiplica los valores de un cromosoma a los del actual.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param aMultiplicar Cromosoma a multiplicar.
	 */
	public void multiplica(Cromosoma aMultiplicar){
		this.comunResolucion(aMultiplicar);
		int tam = 0;
		if(this.completo.length <= aMultiplicar.getCompleto().length) tam = this.completo.length;
		else tam = aMultiplicar.getCompleto().length;
		for(int i = 1; i < tam; i++){
			this.completo[i] *= aMultiplicar.getCompleto()[i];
		}
	}
	
	/**
	 * Función que divide los valores del cromosoma actual entre los del parámetro.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param aDividir Cromosoma divisor.
	 */
	public void divide(Cromosoma aDividir){
		float anterior = 0;
		this.comunResolucion(aDividir);
		int tam = 0;
		if(this.completo.length <= aDividir.getCompleto().length) tam = this.completo.length;
		else tam = aDividir.getCompleto().length;
		for(int i = 1; i < tam; i++){
			try{
				anterior = this.completo[i];
				this.completo[i] /= aDividir.getCompleto()[i];
			}catch(Exception E){
				this.completo[i] = anterior;
			}
		}
		/*for(int i = tam; i < this.completo.length; i++){
			this.completo[i] = 0;
		}*/
	}
	
	/**
	 * Función que suma un numero a todos los elementos del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param numero Número a sumar.
	 */
	public void sumaNumero(float numero){
		for(int i = 0; i < this.completo.length; i++){
			this.completo[i] += numero;
		}
	}
	
	/**
	 * Función que resta un número a todos los elementos del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param numero Número a restar
	 */
	public void restaNumero(float numero){
		for(int i = 0; i < this.completo.length; i++){
			this.completo[i] -= numero;
		}
	}

	/**
	 * Función que todos los elementos del array "completo" por un número.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param numero Número por el que multiplicar.
	 */
	public void multiplicaNumero(float numero){
		for(int i = 0; i < this.completo.length; i++){
			this.completo[i] *= numero;
		}
	}

	/**
	 * Función que divide cada elemento del array "completo" por un número.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param numero Número por el que dividir.
	 */
	public void divideNumero(float numero){
		float anterior = 0;
		for(int i = 0; i < this.completo.length; i++){
			try{
				anterior = this.completo[i];
				this.completo[i] /= numero;
			} catch (Exception E){
				this.completo[i] = anterior;
			}
		}
	}
	
	/**
	 * Función que aplica un filtro por una transformada de Wavelet de Haar Orotogonal.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param limiteWLT Límite de salto wavelet.
	 */
	public void filtroWLT(float limiteWLT){
		
		AncientEgyptianDecomposition t4 = new AncientEgyptianDecomposition(new DiscreteWaveletTransform(new Haar02Orthogonal()));

		this.completo[0] = this.completo[1]; //Como el valor 0 del array no tiene sentido se iguala al valor 1 para que no produzca errores al hacer la transformada.
		float [] arrHil = t4.forwardWavelet(this.completo);
		int tamSubArrays[] = t4.convertInteger2AncientEgyptianMultiplipliers(this.completo.length);
		
		//Se recorren todos los subarrays por niveles de descomposición wavelet para comprobar si el valor
		//es o no es menor que el límite impuesto. Si lo es, se anula.
		int offset = 0;
		for(int i = 0; i < tamSubArrays.length; i++){

			if(i > 0) offset += (int)Math.pow(2, tamSubArrays[i-1]);
						
			int offsetNivel = offset;
			for(int nivel = tamSubArrays[i]; nivel > 0; nivel--){
				int tamNivel = (int)Math.pow(2, tamSubArrays[i]-nivel);
				if(nivel > tamSubArrays[i]) offsetNivel += (int)Math.pow(2, tamSubArrays[i]-nivel+1);
			
				for(int j = 0; j < tamNivel; j++){
					float valor = arrHil[offsetNivel+j]/nivel;
					if(valor < limiteWLT && valor > -limiteWLT){
						arrHil[offsetNivel+j] = 0;
					}
				}
				
			}
		}
		this.completo = t4.reverseWavelet(arrHil);
	}
	
	/**
	 * Función que calcula la media aritmética de los valores del array "completo"
	 * que son superiores a la media pasada como parámetro.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param media Media a comparar.
	 * @return La media de los valores mayores.
	 */
	public float mediaSup(float media){
		float mediaSup = 0;
		int valores = 0;
		for(int i = 1; i < this.completo.length;i++){
			if(this.completo[i] > media){
				mediaSup += this.completo[i];
				valores++;
			}
		}
		mediaSup /= valores;
		return mediaSup;
	}
	
	/**
	 * Función que calcula la media aritmética de los valores del array "completo"
	 * que son inferiores a la media pasada como parámetro.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param media Media a comparar.
	 * @return La media de los valores menores.
	 */
	public float mediaInf(float media){
		float mediaInf = 0;
		int valores = 0;
		for(int i = 1; i < this.completo.length;i++){
			if(this.completo[i] < media){
				mediaInf += this.completo[i];
				valores++;
			}
		}
		mediaInf /= valores;
		return mediaInf;
	}
	
	/**
	 * Función que calcula la media aritmética de los valores del array "completo"
	 * que son superiores a la media aritmética del array.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return La media de los valores mayores.
	 */
	public float mediaSup(){
		float mediaSup = 0;
		float media = this.media();
		int valores = 0;
		for(int i = 1; i < this.completo.length;i++){
			if(this.completo[i] > media){
				mediaSup += this.completo[i];
				valores++;
			}
		}
		mediaSup /= valores;
		return mediaSup;
	}
	
	/**
	 * Función que calcula la media aritmética de los valores del array "completo"
	 * que son inferiores a la media aritmética del array.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return La media de los valores menores.
	 */
	public float mediaInf(){
		float mediaInf = 0;
		float media = this.media();
		int valores = 0;
		for(int i = 1; i < this.completo.length;i++){
			if(this.completo[i] < media){
				mediaInf += this.completo[i];
				valores++;
			}
		}
		mediaInf /= valores;
		return mediaInf;
	}
	
	/**
	 * Función que calcula la media aritmética del array "completo".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @return La media calculada.
	 */
	public float media(){
		float media = 0;
		for(int i = 1; i < this.completo.length;i++){
			media += this.completo[i];
		}
		media /= this.completo.length - 1;
		return media;
	}
	
	/**
	 * Función que calcula la media aritmética del array "completo" entre las posiciones "inicio" y "fin".
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param inicio Posición de inicio.
	 * @param fin Posición de fin.
	 * @return La media calculada.
	 */
	public float media(int inicio, int fin){
		if(inicio < 0 || inicio >= this.completo.length || fin < inicio || fin >= this.completo.length){
			return 0;
		}
		float media = 0;
		int tam = fin - inicio;
		for(int i = inicio; i <= fin; i++){
			media += this.completo[i];
		}
		media /= tam;
		return media;
	}
	
	/**
	 * Función que busca fragmentos de expresión en el array "completo"
	 * basándose en la transformada de wavelet y utilizando los parámetros
	 * para ajustar la búsqueda.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param limiteExpWLT Límite del salto mínimo para que se considere como tal.
	 * @param limiteExpMedia Límite de la media para aceptar o no la expresión.
	 * @return Un array de fragmentos expresados encontrados.
	 */
	public FragConocido [] buscaExpresionWLT(float limiteExpWLT, float limiteExpMedia){
		
		AncientEgyptianDecomposition t4 = new AncientEgyptianDecomposition(new DiscreteWaveletTransform(new Haar02Orthogonal()));
		
		this.completo[0] = this.completo[1]; //Se iguala el índice 0 al 1 para que no interfiera en la transformada
		
		int tamSubArrays[] = t4.convertInteger2AncientEgyptianMultiplipliers(this.completo.length); //Se obtienen los coeficientes egipcios de descomposición del array.
		
		int tam = (int)Math.pow(2, tamSubArrays[0]); //Se calcula el tamaño de las 2 mitades en que se dividirá el array para la búsqueda de saltos.
		
		float [] arrHil1 = new float[tam];
		float [] arrHil2 = new float[tam];
		
		ArrayList<FragConocido> f = new ArrayList<FragConocido>(); // Aquí se guardarán los fragmentos según se vayan encontrando.
		
		HashMap<Integer, Boolean> cortes = new HashMap<Integer, Boolean>(); //Aquí se guardaran las posiciones de los saltos y si es hacía arriba (true) o hacía abajo (false)
		
		//Se rellenenan los dos arrays
		System.arraycopy(this.completo, 0, arrHil1, 0, (int)Math.pow(2,tamSubArrays[0]));
		System.arraycopy(this.completo, this.completo.length-(int)Math.pow(2,tamSubArrays[0]), arrHil2, 0, (int)Math.pow(2,tamSubArrays[0]));
		
		//Se les aplica la transformada
		arrHil1 = t4.forwardWavelet(arrHil1);
		arrHil2 = t4.forwardWavelet(arrHil2);
		
		int offset = this.completo.length-(int)Math.pow(2,tamSubArrays[0]); //Offset del 2º array dentro del array "completo".
		
		//Se recorre por niveles ambos arrays simultáneamente.
		int offsetNivel = 0;
		int tamNivel = 0;
		float valor = 0;
		for(int nivel = tamSubArrays[0]; nivel > 2; nivel--){
			tamNivel = (int)Math.pow(2, tamSubArrays[0]-nivel);
			for(int e = 1; e <= tamNivel; e++){
				
				//Array 1
				valor = arrHil1[offsetNivel+e]/nivel;
				if(valor < -limiteExpWLT){ //Si el valor del salto dividido por el nivel actual es menor que -limiteExpWLT es que el salto es positivo y se debe buscar su posición más ajustada
					int v = bajaNivel(0, nivel, e, tamSubArrays[0], arrHil1, true, limiteExpWLT);
					cortes.put(v, true);
					
				}
				else if(valor > limiteExpWLT){ //Si el valor es superior al límite positivo es que el salto es hacía abajo
					cortes.put(bajaNivel(0, nivel, e, tamSubArrays[0], arrHil1, false, limiteExpWLT), false);
				}
				
				//Array 2
				valor = arrHil2[offsetNivel+e]/nivel;
				if(valor < -limiteExpWLT){
					int v = bajaNivel(offset, nivel, e, tamSubArrays[0], arrHil2, true, limiteExpWLT);
					cortes.put(v, true);
					
				}
				else if(valor > limiteExpWLT){
					cortes.put(bajaNivel(offset, nivel, e, tamSubArrays[0], arrHil2, false, limiteExpWLT), false);
				}
			}
			
			offsetNivel +=tamNivel;
		}
		
		TreeSet<Integer> set = new TreeSet<Integer>(cortes.keySet()); //Se crea un TreeSet para que las posiciones de los cortes aparezcan ordenadas al recorrerlas
		Iterator<Integer> it = set.iterator();
		ArrayList<Integer> intervaloA = new ArrayList<Integer>(); //Conjunto de saltos hacía arriba
		ArrayList<Integer> intervaloC = new ArrayList<Integer>(); //Conjunto de saltos hacía abajo.
		
		while(it.hasNext()){
			int numero = it.next();
			
			if(cortes.get(numero)){//Si es un salto hacía arriba
				
				if(!intervaloC.isEmpty()){//Si hay cortes hacía abajo anteriores (hemos cerrado un intervalo ya, realizamos el procesamiento
					float maxMedia = 0, mediaCalc;
					int aMax = 0, cMax = 0, maxTam = 0;
					
					//Acota por la izquierda eliminando todos los valores que sean menores del límite dejando al menos el último
					for(int i=0; i < intervaloA.size()-1; i++){
						if(this.completo[intervaloA.get(i)] < limiteExpMedia){
							intervaloA.remove(i);
							i--;
						}
					}
					
					//Acota el intervalo por la derecha dejando al menos el primer valor
					for(int i=intervaloC.size()-1; i >= 0 && intervaloC.size() > 0; i--){
						if(this.completo[intervaloC.get(i)] > limiteExpMedia){
							//System.out.println("ELIMINANDO ELEMENTO " + intervaloC.size() + " -> " + (intervaloC.size()-1) + " " + i);
							intervaloC.remove(i);
						}
						
					}
					
					//Con lo que quede haz el intervalo más grande posible cuya medía sea mayor que el límite
					for(int i=0; i < intervaloA.size(); i++){
						for(int j = 0; j < intervaloC.size();j++/*int j = intervaloC.size()-1; j < 1; j++*/){
							//if(media(intervaloC.get(j-1), intervaloC.get(j)) < LIMITE_EXP_MEDIA) continue;
							mediaCalc = this.media(intervaloA.get(i), intervaloC.get(j));
							if(mediaCalc > limiteExpMedia && (intervaloC.get(j) - intervaloA.get(i)) > maxTam){
								maxMedia = mediaCalc;
								maxTam = (cMax - aMax);
								aMax = intervaloA.get(i);
								cMax = intervaloC.get(j);
							}
						}
					}
					
					if(maxMedia > limiteExpMedia && maxTam*this.getResolucion() >= LIMITE_TAM){
						f.add(new FragConocido(new Fragmento(aMax*this.getResolucion(), cMax*this.getResolucion(), '.')));
						f.get(f.size()-1).setCromosoma(this.cromosoma);
						f.get(f.size()-1).setDireccion(this.direccion);
					}
					if(!intervaloC.isEmpty()){
						if(maxTam*this.getResolucion() >= LIMITE_TAM)intervaloA.clear();
						intervaloC.clear();
					}
				}//FIN DE if(!intervaloC.isEmpty()){
				
				intervaloA.add(numero); //Añade número a IntervaloA ya que es un salto hacía arriba
				
				while(it.hasNext()){//Mientras haya valores sin tratar
					numero = it.next();
					//System.out.println(numero + " " + cortes.get(numero));
					
					if(!cortes.get(numero)){//Si es un salto hacía abajo
						
						intervaloC.clear(); //Se borra lo que hubiera en intervaloC porque es el primer salto hacía abajo
						intervaloC.add(numero);//Añadelo a intervaloC y sal del bucle
						
						//frag.setFin(numero*this.getResolucion());
						//f.add(new FragConocido(frag));
						//f.get(f.size()-1).setCromosoma("chromosome1");
						break;
					}else{//Si es salto hacía arriba
						intervaloA.add(numero); //Añadelo a intervaloA y sigue con el bucle
					}
					//else frag.setInicio(numero*this.resolucion);
				}//Fin bucle interno de saltos hacía arriba
			}else{ //Si no era un salto hacía arriba
				if(!intervaloC.isEmpty()){ //Si intervaloC no está vacío (viene de haber cerrado un salto antes)
					intervaloC.add(numero); //Añade el número al conjunto
				}
			}
			
		}
		
		//Se pasan a un array los fragmentos encontrados en el array "completo" que están en un ArrayList
		FragConocido [] fR = new FragConocido[f.size()];
		for(int i = 0; i < f.size(); i++){
			fR[i] = f.get(i);
		}
		return fR;
	}
	
	/**
	 * Función recursiva que va descendiendo niveles en el ArrHil buscando el límite más acotado de un salto.
	 * 
	 * @param offsetArray Offset respecto al Array de tiempo correspondiente al ArrHil con que se trabaja.
	 * @param nivelActual Nivel actual de recorrido.
	 * @param elementoActual Elemento dentro del nivel actual.
	 * @param nivelMax Máximo nivel del ArrHil.
	 * @param arrHil ArrHil con los elementos que se deben recorrer.
	 * @param negativo Si es un salto hacía arriba (true) o hacía abajo (false).
	 * @param limiteExpWLT Límite del salto (debe ser el valor absoluto del límite).
	 * @return La posicion del Array de tiempo en que se localiza el corte.
	 */
	private int bajaNivel(int offsetArray, int nivelActual, int elementoActual, int nivelMax, float [] arrHil, boolean negativo, float limiteExpWLT){
		if(nivelActual < 2 || nivelActual > nivelMax) return -1; //Condición de salida si estás en el nivel 1 o te pasan un nivel mayor que el máximo.
		
		int elementoCorteT = offsetArray + (int)Math.pow(2, nivelActual-1)*(2*elementoActual - 1); //Elemento de corte según el elemento y nivel actual.
		if(!negativo) elementoCorteT--; //Si el salto el hacía abajo ajustas por la izquierda.
		
		int elementoNivelSigH = 2*elementoActual - 1; //Primero de los 2 elementos del nivel siguiente correspondientes a al elememento y nivel actuales.
		int posElementoNivelSigH = (int)Math.pow(2, nivelMax - nivelActual - 1) + elementoNivelSigH - 1; //Posición del elemento anterior dentro del arrHil.
		
		int aux;
		
		if(negativo){ //Si el salto es hacía arriba miras los dos elementos siguientes, buscando que sigan manteniendo un valor de salto mayor (en valor absoluto) que el límite, si es así bajas un nivel.
			if(arrHil[posElementoNivelSigH]/(nivelActual-1) < -limiteExpWLT){
				aux = bajaNivel(offsetArray, nivelActual-1, elementoNivelSigH, nivelMax, arrHil,negativo, limiteExpWLT);
			}else if(arrHil[posElementoNivelSigH+1]/(nivelActual-1) < -limiteExpWLT){
				aux = bajaNivel(offsetArray, nivelActual-1, elementoNivelSigH+1, nivelMax, arrHil,negativo, limiteExpWLT);
			}
			else return elementoCorteT;
		} else{ //Igual para saltos hacía abajo mirando los elementos en orden inverso.
			if(arrHil[posElementoNivelSigH+1]/(nivelActual-1) > limiteExpWLT){
				aux = bajaNivel(offsetArray, nivelActual-1, elementoNivelSigH+1, nivelMax, arrHil,negativo, limiteExpWLT);
			}else if(arrHil[posElementoNivelSigH]/(nivelActual-1) > limiteExpWLT){
				aux = bajaNivel(offsetArray, nivelActual-1, elementoNivelSigH, nivelMax, arrHil,negativo, limiteExpWLT);
			}
			else return elementoCorteT;
		}
		
		if(aux == -1){
			return elementoCorteT;
		}
		return aux;
	}
	
	/**
	 * Función que busca fragmentos de expresión en el array "completo" a través del algoritmo de la media.
	 * 
	 * @date 01.08.2012
	 * @author Enrique Vázquez de Luis
	 * @param limiteExpMedia Límite mímino de valor de los elementos para que se consideren expresados.
	 * @return La colección de fragmentos encontrados en la búsqueda.
	 */
	public FragConocido[] buscaExpresionSencillo(float limiteExpMedia){
		ArrayList<FragConocido> fragmentos = new ArrayList<FragConocido>();
		int inicioFrag, tamFrag;
		float media = 0;
		boolean fragCompleto;
		
		for(int i = 1; i < this.completo.length; i++){
			inicioFrag = 0;
			tamFrag = 0;
			fragCompleto = false;
			media = 0;
			int tamNoExpresado;
			
			if(this.completo[i] > limiteExpMedia){
				inicioFrag= i;
				tamFrag = 1;
				media += this.completo[i];
				tamNoExpresado = 0;
				
				while(i < this.completo.length && !fragCompleto){
					if(this.completo[i] > limiteExpMedia){
						tamNoExpresado = 0; 
					} else{
						tamNoExpresado++;
					}
					if(tamNoExpresado*this.resolucion > LIMITE_TAM_NO_EXPRESADO){
						tamFrag -= tamNoExpresado;
						if(tamFrag*this.resolucion > LIMITE_TAM)fragCompleto = true;
						break;
					}
					tamFrag++;
					media += this.completo[i];
					i++;
				}
				if(fragCompleto){
					if(media >= limiteExpMedia){
						fragmentos.add(new FragConocido(new Fragmento(inicioFrag*this.resolucion, (inicioFrag+tamFrag)*this.resolucion, '+')));
						fragmentos.get(fragmentos.size()-1).setCromosoma(this.cromosoma);
						fragmentos.get(fragmentos.size()-1).setDireccion(this.direccion);
					}
					
				}
			}
			
		}
		
		FragConocido [] fR = new FragConocido[fragmentos.size()];
		for(int i = 0; i < fragmentos.size(); i++){
			fR[i] = fragmentos.get(i);
		}
		return fR;
	}
	
	/**
	 * Función Main para pruebas unitarias.
	 * @param args
	 */
	public static void main(String[] args) {
		
		//DNA_Schizosaccharomyces_pombe adn = new DNA_Schizosaccharomyces_pombe("exp1_Mei0h.wig");
		//adn.expresion();
		
		Cromosoma dna = new Cromosoma();
		dna.leerFicheroExpresion("exp1_Mei0h.wig");
		dna.rellenaCompletoSondas();
		
		//dna.reduceResolucion(25);
		dna.eliminaErroneos(25);
		
		dna.filtroWLT(Cromosoma.LIMITE_WLT_MIN);
		
		dna.bandwith(25);
		dna.reduceResolucion(25);
		dna.filtroWLT(Cromosoma.LIMITE_WLT_MIN);
		dna.D_printFileCompleto(System.getProperty("user.home")+"/SalidaWWLT_NUEVA.wig");
		
		FragConocido [] fragmentos = dna.buscaExpresionSencillo(Cromosoma.LIMITE_EXP_MEDIA);
		String [] cadenas = new String[4];
		cadenas[0] = "##gff-version 3";
		cadenas[1] = "##sequence-region chromosome1 1 5579133";
		GFFFileIO.escribeEnFichero("CDS_Generado3NUEVA_MEDIA.gff", fragmentos, cadenas);
		
		
		dna.leerFicheroExpresion("exp1_Mei0h.wig");
		dna.rellenaCompletoSondas();
		
		//dna.reduceResolucion(25);
		dna.eliminaErroneos(25);
		
		dna.filtroWLT(Cromosoma.LIMITE_WLT_MIN);
		
		dna.bandwith(25);
		//fragmentos = dna.buscaExpresionWLT(Cromosoma.LIMITE_EXP_WLT, Cromosoma.LIMITE_EXP_WLT);
		//GFFFileIO.escribeEnFichero("CDS_GeneradoWLTOrt5.gff", fragmentos, cadenas);
		
		/*FragConocido [] fragmentos = GFFFileIO.leerDeFichero("CDS.gff");
		Fragmento f = fragmentos[1];
		System.out.println(f.getFin() + " " + f.getInicio());
		for(int i = 0; i < fragmentos.length; i++) fragmentos[i].setIntensidad((int)(Math.random()*1000));
		String [] cadenas = new String[4];
		cadenas[0] = "##gff-version 3";
		cadenas[1] = "##sequence-region chromosome1 1 5579133";
		cadenas[2] = "##sequence-region chromosome2 1 4539804";
		cadenas[3] = "##sequence-region chromosome3 1 2452883";
		GFFFileIO.escribeEnFichero("CDS3.gff", fragmentos, cadenas);*/
		
		//dna.compruebaSondas();
		
		/*dna.reduceResolucion2();
		dna.reduceResolucion3();
		dna.reduceResolucion2();
		dna.reduceResolucion2();*/
		//dna.bandwith(50);
		
		/*dna.bandwith(50);
		dna.reduceResolucion(500);
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida500i.wig");
		dna.WLT();
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida500iWLT.wig");

		dna.aumentaResolucion(4);
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida125i.wig");
		dna.WLT();
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida125iWLT.wig");*/
		
		/*DNA_Sacharomices dnaCompleto = new DNA_Sacharomices();
		dnaCompleto.leerFicheroExpresion("exp1_DNA.wig");
		dnaCompleto.rellenaCompletoSondas();
		
		dna.D_printFileCompleto(System.getProperty("user.home")+"/SalidaSinDividir.wig");
		dna.divide(dnaCompleto);
		dna.D_printFileCompleto(System.getProperty("user.home")+"/SalidaDividida.wig");*/

		
/*		dna.bandwith(50);
		dna.reduceResolucion(250);
		
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida250BG50.wig");
		
		DNA_Sacharomices dna2 = new DNA_Sacharomices();
		dna2.leerFicheroExpresion("Me0h.wig");
		dna2.rellenaCompletoSondas();

		dna2.reduceResolucion(125);
		dna.comunResolucion(dna2);
		
		dna.D_printFileCompleto(System.getProperty("user.home")+"/Salida125.wig");
		
		dna.WLT();
		dna.D_printFileCompleto(System.getProperty("user.home")+"/SalidaWLT.wig");*/
		
		System.out.println(dna.media());
		System.out.println(dna.mediaSup());
		System.out.println(dna.mediaInf());
		
		System.out.println("FINALIZADO");
	}

}
